package handlers

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"ticket/internal/db"
	"ticket/internal/db/model"
	"ticket/internal/schemas"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
)

type LoginHandler struct{}

func RegisterLoginRouter(group *gin.RouterGroup) {
	service := &LoginHandler{}
	group.POST("login", service.Login)
	group.POST("logout", service.Logout)
	group.POST("upload_annex", service.UploadAnnex)
	group.GET("download_annex", service.DownloadAnnex)
}

// Login godoc
// @Summary 登陆
// @Description 登陆
// @Tags 登陆
// @ID /login
// @Accept json
// @Produce json
// @Param data body schemas.LoginInput true "body"
// @Success 200 {object} schemas.Response{data=schemas.LoginOutput} "success"
// @Router /login [post]
func (service *LoginHandler) Login(ctx *gin.Context) {
	params := &schemas.LoginInput{}
	if err := params.BindValidParam(ctx); err != nil {
		schemas.ResponseError(ctx, schemas.LoginParamInvalid, err)
		return
	}

	// 判断用户是否存在
	user := &model.User{}
	user, err := user.GetByUserName(db.GormDB, params.UserName)
	if err != nil {
		schemas.ResponseError(ctx, schemas.UserNotExist, err)
		return
	}

	if !user.CheckPassword(params.Password) {
		schemas.ResponseError(ctx, schemas.UserPasswordError, err)
		return
	}

	// 登录成功，设置cookie，跳转到首页
	session := sessions.Default(ctx)
	session.Set("username", user.UserName)
	session.Set("user_id", user.ID)
	session.Save()
	schemas.ResponseSuccess(ctx, gin.H{
		"username": user.UserName,
		"nickname": user.NickName,
		"issuper":  user.IsSuper,
		"email":    user.Email,
	})
}

// Logout godoc
// @Summary 退出
// @Description 退出
// @Tags 退出
// @ID /logout
// @Accept json
// @Produce json
// @Success 200 {object} schemas.Response{data=schemas.Empty} "success"
// @Router /logout [post]
func (service *LoginHandler) Logout(ctx *gin.Context) {
	session := sessions.Default(ctx)
	session.Clear()
	session.Save()
	schemas.ResponseSuccess(ctx, nil)
}

// UploadAnnex godoc
// @Summary 上传附件
// @Description 上传附件
// @Tags 附件
// @ID /upload_annex
// @Accept json
// @Produce json
// @Param file formData file true "附件"
// @Success 200 {object} schemas.Response{data=string} "附件上传成功"
// @Router /upload_annex [post]
func (h *LoginHandler) UploadAnnex(ctx *gin.Context) {
	file, err := ctx.FormFile("file")
	if err != nil {
		schemas.ResponseError(ctx, schemas.AnnexParamInvalid, err)
		return
	}

	// 打开上传文件
	openFile, err := file.Open()
	if err != nil {
		schemas.ResponseError(ctx, schemas.OpenFileFailed, err)
		return
	}
	defer openFile.Close()

	// 计算文件的 MD5 值
	hash := md5.New()
	if _, err := io.Copy(hash, openFile); err != nil {
		schemas.ResponseError(ctx, schemas.OpenFileFailed, err)
		return
	}
	md5Hash := hex.EncodeToString(hash.Sum(nil))

	// 重置文件指针到开头
	if _, err := openFile.Seek(0, io.SeekStart); err != nil {
		schemas.ResponseError(ctx, schemas.OpenFileFailed, err)
		return
	}

	// 获取文件后缀
	ext := filepath.Ext(file.Filename)

	// 定义保存文件的路径
	annexPath := viper.GetString("service.annex_path")
	if err := os.MkdirAll(annexPath, os.ModePerm); err != nil {
		schemas.ResponseError(ctx, schemas.CreateDirFailed, err)
		return
	}

	// 保存文件
	filePath := fmt.Sprintf("%s/%s%s", annexPath, md5Hash, ext)
	saveFile, err := os.Create(filePath)
	if err != nil {
		schemas.ResponseError(ctx, schemas.CreateFileFailed, err)
		return
	}
	defer saveFile.Close()

	_, err = io.Copy(saveFile, openFile)
	if err != nil {
		schemas.ResponseError(ctx, schemas.CopyFileFailed, err)
		return
	}

	// 构建文件请求地址
	requestPath := fmt.Sprintf("/download_annex?md5=%s&filename=%s", md5Hash, file.Filename)
	schemas.ResponseSuccess(ctx, requestPath)
}

// DownloadAnnex godoc
// @Summary 下载附件
// @Description 下载附件
// @Tags 附件
// @ID /download_annex
// @Param md5 query string true "附件MD5值"
// @Param filename query string true "附件文件名"
// @Success 200 {object} schemas.Response{data=schemas.Empty} "附件下载成功"
// @Router /download_annex [get]
func (h *LoginHandler) DownloadAnnex(ctx *gin.Context) {
	md5Hash := ctx.Query("md5")
	filename := ctx.Query("filename")

	ext := filepath.Ext(filename)
	// 构建文件路径
	annexPath := viper.GetString("service.annex_path")
	filePath := fmt.Sprintf("%s/%s%s", annexPath, md5Hash, ext)

	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		schemas.ResponseError(ctx, schemas.FileNotFound, err)
		return
	}
	defer file.Close()

	// 获取文件信息
	fileInfo, err := file.Stat()
	if err != nil {
		schemas.ResponseError(ctx, schemas.GetFileInfoFailed, err)
		return
	}

	// 设置响应头
	ctx.Header("Content-Type", "application/octet-stream")
	ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
	ctx.Header("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))
	ctx.File(filePath)
}
